package com.zsy._13并发包_ForkJoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

/**
 * 目标 ForkJoin
 *
 * 作用：将大任务拆分成小任务，体现递归的思想。
 *
 * 特点：工作窃取。
 * 里面维护的是一个双端队列，例如线程 A、B 分别执行两个队列的任务，当线程 B 优先执行完，
 * 可以窃取 线程 A 正在执行队列尾部的任务执行，从而提高效率。
 *
 * 使用：使用时可以继承 ForkJoinTask 的两个子类中的其中一个
 * 1. RecursiveAction   递归事件，没有返回值
 * 2. RecursiveTask<V>  递归任务，有返回值
 *
 * 举例，使用三种方法计算从 0-10 亿的累加求和
 * 方法1. 直接累加
 * 方法2. 使用 ForkJoinTask 实现类计算
 * 方法3. 使用 Stream 流计算
 *
 *
 * @author: zhangshuaiyin
 * @date: 2021/8/25 20:05
 */
public class ForkJoinDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println(testAdd()); // 240
        System.out.println(testForkJoin()); // 2
        System.out.println(testStream()); // 150
    }

    public static Long testAdd() {
        long sum = 0L;
        long start = System.currentTimeMillis();
        for (long i = 1; i <= 10_0000_0000L; i++) {
            sum += i;
        }
        System.out.println("方法1 - 直接累加用时：" + (System.currentTimeMillis() - start));
        return sum;
    }

    public static Long testForkJoin() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTaskDemo forkJoinTask = new ForkJoinTaskDemo(1L, 10_0000_0000L);
        ForkJoinTask<Long> result = forkJoinPool.submit(forkJoinTask);
        System.out.println("方法2 - ForkJoinTask 用时：" + (System.currentTimeMillis() - start));
        return result.get();
    }

    public static Long testStream() {
        long start = System.currentTimeMillis();
        // Stream并行流 () (]
        long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);
        System.out.println("方法3 - LongStream 用时：" + (System.currentTimeMillis() - start));
        return sum;
    }
}
